using System;
namespace ch.ethz.ssh2.crypto.cipher
{
	
	/// <summary> BlockCipherFactory.
	/// 
	/// </summary>
	/// <author>  Christian Plattner
	/// </author>
	/// <version>  2.50, 03/15/10
	/// </version>
	public class BlockCipherFactory
	{
		public static System.String[] DefaultCipherList
		{
			get
			{
				System.String[] list = new System.String[ciphers.Count];
				for (int i = 0; i < ciphers.Count; i++)
				{
					CipherEntry ce = (CipherEntry) ciphers[i];
					list[i] = new System.Text.StringBuilder(ce.type).ToString();
				}
				return list;
			}
			
		}
		internal class CipherEntry
		{
			internal System.String type;
			internal int blocksize;
			internal int keysize;
			internal System.String cipherClass;
			
			public CipherEntry(System.String type, int blockSize, int keySize, System.String cipherClass)
			{
				this.type = type;
				this.blocksize = blockSize;
				this.keysize = keySize;
				this.cipherClass = cipherClass;
			}
		}
		
		internal static System.Collections.ArrayList ciphers = System.Collections.ArrayList.Synchronized(new System.Collections.ArrayList(10));
		
		public static void  checkCipherList(System.String[] cipherCandidates)
		{
			for (int i = 0; i < cipherCandidates.Length; i++)
				getEntry(cipherCandidates[i]);
		}
		
		public static BlockCipher createCipher(System.String type, bool encrypt, byte[] key, byte[] iv)
		{
			try
			{
				CipherEntry ce = getEntry(type);
				//UPGRADE_TODO: The differences in the format  of parameters for method 'java.lang.Class.forName'  may cause compilation errors.  "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1092'"
				System.Type cc = System.Type.GetType(ce.cipherClass);
				BlockCipher bc = (BlockCipher) System.Activator.CreateInstance(cc);
				
				if (type.EndsWith("-cbc"))
				{
					bc.init(encrypt, key);
					return new CBCMode(bc, iv, encrypt);
				}
				else if (type.EndsWith("-ctr"))
				{
					bc.init(true, key);
					return new CTRMode(bc, iv, encrypt);
				}
				throw new System.ArgumentException("Cannot instantiate " + type);
			}
			catch (System.Exception e)
			{
				throw new System.ArgumentException("Cannot instantiate " + type);
			}
		}
		
		private static CipherEntry getEntry(System.String type)
		{
			for (int i = 0; i < ciphers.Count; i++)
			{
				CipherEntry ce = (CipherEntry) ciphers[i];
				if (ce.type.Equals(type))
					return ce;
			}
			throw new System.ArgumentException("Unkown algorithm " + type);
		}
		
		public static int getBlockSize(System.String type)
		{
			CipherEntry ce = getEntry(type);
			return ce.blocksize;
		}
		
		public static int getKeySize(System.String type)
		{
			CipherEntry ce = getEntry(type);
			return ce.keysize;
		}
		static BlockCipherFactory()
		{
			{
				/* Higher Priority First */
				
				ciphers.Add(new CipherEntry("aes256-ctr", 16, 32, "ch.ethz.ssh2.crypto.cipher.AES"));
				ciphers.Add(new CipherEntry("aes192-ctr", 16, 24, "ch.ethz.ssh2.crypto.cipher.AES"));
				ciphers.Add(new CipherEntry("aes128-ctr", 16, 16, "ch.ethz.ssh2.crypto.cipher.AES"));
				ciphers.Add(new CipherEntry("blowfish-ctr", 8, 16, "ch.ethz.ssh2.crypto.cipher.BlowFish"));
				
				ciphers.Add(new CipherEntry("aes256-cbc", 16, 32, "ch.ethz.ssh2.crypto.cipher.AES"));
				ciphers.Add(new CipherEntry("aes192-cbc", 16, 24, "ch.ethz.ssh2.crypto.cipher.AES"));
				ciphers.Add(new CipherEntry("aes128-cbc", 16, 16, "ch.ethz.ssh2.crypto.cipher.AES"));
				ciphers.Add(new CipherEntry("blowfish-cbc", 8, 16, "ch.ethz.ssh2.crypto.cipher.BlowFish"));
				
				ciphers.Add(new CipherEntry("3des-ctr", 8, 24, "ch.ethz.ssh2.crypto.cipher.DESede"));
				ciphers.Add(new CipherEntry("3des-cbc", 8, 24, "ch.ethz.ssh2.crypto.cipher.DESede"));
			}
		}
	}
}